package controllers

import (
	"go-admin-system/config"
	"gorm.io/gorm"
	"net/http"
	"time"

	"github.com/gin-gonic/gin"
	"go-admin-system/middleware"
	"go-admin-system/models"
	"go-admin-system/utils"
	"go.uber.org/zap"
)

type AuthController struct {
	DB     *gorm.DB
	Logger *zap.Logger
}

func NewAuthController(db *gorm.DB, logger *zap.Logger) *AuthController {
	return &AuthController{
		DB:     db,
		Logger: logger,
	}
}

// 用户登录
func (ac *AuthController) Login(c *gin.Context) {
	// 记录开始时间
	startTime := time.Now()

	var loginInput struct {
		Username string `json:"username" binding:"required"`
		Password string `json:"password" binding:"required"`
	}

	if err := c.ShouldBindJSON(&loginInput); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "请求参数错误"})
		ac.Logger.Warn("登录接口 [参数解析失败]",
			zap.String("event", "login_param_error"),
			zap.String("username", loginInput.Username),
			zap.String("ip", c.ClientIP()),
			zap.Duration("duration", time.Since(startTime)),
			zap.Error(err),
		)
		return
	}

	ac.Logger.Info("登录接口 [接收请求]",
		zap.String("event", "login_request_received"),
		zap.String("username", loginInput.Username),
		zap.String("ip", c.ClientIP()),
		zap.Duration("duration", time.Since(startTime)),
	)

	var user models.User
	// 记录数据库查询开始时间
	dbStartTime := time.Now()
	if err := ac.DB.Where("username = ?", loginInput.Username).First(&user).Error; err != nil {
		c.JSON(http.StatusUnauthorized, gin.H{"error": "用户名或密码错误"})
		ac.Logger.Warn("登录接口 [用户查询失败]",
			zap.String("event", "login_user_not_found"),
			zap.String("username", loginInput.Username),
			zap.String("ip", c.ClientIP()),
			zap.Duration("total_duration", time.Since(startTime)),
			zap.Duration("db_duration", time.Since(dbStartTime)),
		)
		return
	}
	dbDuration := time.Since(dbStartTime)

	ac.Logger.Info("登录接口 [用户查询成功]",
		zap.String("event", "login_user_found"),
		zap.String("username", loginInput.Username),
		zap.Uint("user_id", user.ID),
		zap.String("ip", c.ClientIP()),
		zap.Duration("db_duration", dbDuration),
	)

	// 验证密码 - 记录密码验证开始时间
	pwdStartTime := time.Now()
	if !utils.CheckPasswordHash(loginInput.Password, user.Password) {
		c.JSON(http.StatusUnauthorized, gin.H{"error": "用户名或密码错误"})
		ac.Logger.Warn("登录接口 [密码验证失败]",
			zap.String("event", "login_password_invalid"),
			zap.String("username", loginInput.Username),
			zap.Uint("user_id", user.ID),
			zap.String("ip", c.ClientIP()),
			zap.Duration("total_duration", time.Since(startTime)),
			zap.Duration("pwd_duration", time.Since(pwdStartTime)),
		)
		return
	}
	pwdDuration := time.Since(pwdStartTime)

	ac.Logger.Info("登录接口 [密码验证成功]",
		zap.String("event", "login_password_valid"),
		zap.String("username", loginInput.Username),
		zap.Uint("user_id", user.ID),
		zap.String("ip", c.ClientIP()),
		zap.Duration("pwd_duration", pwdDuration),
	)

	// 生成JWT Token
	tokenStartTime := time.Now()
	cfg := config.GetConfig()
	token, err := middleware.GenerateToken(user.ID, user.RoleID, cfg.JWTSecret, time.Hour*24)
	tokenDuration := time.Since(tokenStartTime)

	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "生成token失败"})
		ac.Logger.Error("登录接口 [Token生成失败]",
			zap.String("event", "login_token_error"),
			zap.Uint("user_id", user.ID),
			zap.String("username", user.Username),
			zap.String("ip", c.ClientIP()),
			zap.Duration("total_duration", time.Since(startTime)),
			zap.Duration("token_duration", tokenDuration),
			zap.Error(err),
		)
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"token": token,
		"user":  user,
	})

	ac.Logger.Info("登录接口 [登录成功]",
		zap.String("event", "login_success"),
		zap.Uint("user_id", user.ID),
		zap.String("username", user.Username),
		zap.Uint("role_id", user.RoleID),
		zap.String("ip", c.ClientIP()),
		zap.Duration("total_duration", time.Since(startTime)),
		zap.Duration("db_duration", dbDuration),
		zap.Duration("pwd_duration", pwdDuration),
		zap.Duration("token_duration", tokenDuration),
	)
}
